package luke.audio.processing;

import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;

import java.io.File;
import java.util.List;

import luke.system.callback.ProgressCallback;

public class JavaCVProcessor {

    /**
     * 使用JavaCV合并多个音频文件（支持WAV、MP3、FLAC等格式）
     * @param inputFiles 输入音频文件列表
     * @param outputPath 输出合并后的音频文件路径
     * @throws Exception 处理过程中的异常（文件不存在、格式不支持等）
     */
    public void concatAudioFilesWithJavaCV(List<File> inputFiles, String outputPath) throws Exception {
        concatAudioFilesWithJavaCV(inputFiles, outputPath, null);
    }
    
    /**
     * 使用JavaCV合并多个音频文件（支持WAV、MP3、FLAC等格式）
     * @param inputFiles 输入音频文件列表
     * @param outputPath 输出合并后的音频文件路径
     * @param progressCallback 进度回调接口
     * @throws Exception 处理过程中的异常（文件不存在、格式不支持等）
     */
    public void concatAudioFilesWithJavaCV(List<File> inputFiles, String outputPath, ProgressCallback progressCallback) throws Exception {
        if (inputFiles == null || inputFiles.isEmpty()) {
            throw new IllegalArgumentException("输入音频文件列表不能为空");
        }

        // 1. 初始化第一个音频的抓取器，用于获取输出参数（采样率、声道数等）
        FFmpegFrameGrabber firstGrabber = new FFmpegFrameGrabber(inputFiles.get(0));
        firstGrabber.start();

        // 2. 初始化输出录制器，参数与第一个音频保持一致（确保格式兼容）
        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputPath, firstGrabber.getAudioChannels());
        recorder.setFormat(getFileFormat(outputPath)); // 自动识别输出格式（如wav、mp3）
        
        // 根据输出格式设置相应的音频编解码器和采样格式
        String outputFormat = getFileFormat(outputPath).toLowerCase();
        switch (outputFormat) {
            case "mp3":
                recorder.setAudioCodec(avcodec.AV_CODEC_ID_MP3);
                recorder.setSampleFormat(avutil.AV_SAMPLE_FMT_FLTP); // MP3需要FLTP格式
                break;
            case "wav":
                recorder.setAudioCodec(avcodec.AV_CODEC_ID_PCM_S16LE); // WAV使用PCM编解码器
                recorder.setSampleFormat(avutil.AV_SAMPLE_FMT_S16); // WAV使用S16格式
                break;
            case "mp4":
            case "m4a":
                // MP4/M4A使用AAC编解码器
                recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
                recorder.setSampleFormat(avutil.AV_SAMPLE_FMT_FLTP); // AAC使用FLTP格式
                break;
            default:
                // 对于其他格式，默认使用AAC编解码器和FLTP格式，以提高兼容性
                recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
                recorder.setSampleFormat(avutil.AV_SAMPLE_FMT_FLTP);
                break;
        }
        
        recorder.setSampleRate(firstGrabber.getSampleRate());
        recorder.setAudioBitrate(firstGrabber.getAudioBitrate());
        
        // 显式禁用视频流以避免"No video output stream"错误
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_NONE);
        recorder.setVideoBitrate(0);
        recorder.setFrameRate(0);
        recorder.setVideoQuality(0);
        recorder.setVideoOption("threads", "0");
        
        recorder.start();

        try {
            // 3. 先写入第一个音频的所有帧
            Frame frame;
            int totalFiles = inputFiles.size();
            int currentFileIndex = 0;
            
            // 更新进度：开始处理第一个文件
            if (progressCallback != null) {
                progressCallback.onProgress("处理文件 1/" + totalFiles, 0);
            }
            
            while ((frame = firstGrabber.grabSamples()) != null) {
                recorder.record(frame);
            }
            firstGrabber.stop();
            currentFileIndex++;

            // 4. 依次写入后续音频的所有帧
            for (int i = 1; i < inputFiles.size(); i++) {
                File inputFile = inputFiles.get(i);
                
                // 更新进度：开始处理当前文件
                if (progressCallback != null) {
                    double progress = (double) currentFileIndex / totalFiles * 100;
                    progressCallback.onProgress("处理文件 " + (currentFileIndex + 1) + "/" + totalFiles, progress);
                }
                
                try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile)) {
                    grabber.start();

                    // 校验采样率和声道数是否与第一个音频一致（避免合并后音质异常）
                    if (grabber.getSampleRate() != recorder.getSampleRate()
                            || grabber.getAudioChannels() != recorder.getAudioChannels()) {
                        throw new RuntimeException("音频格式不兼容：" + inputFile.getName()
                                + "（需与第一个文件保持相同采样率和声道数）");
                    }

                    // 写入当前音频的帧
                    while ((frame = grabber.grabSamples()) != null) {
                        recorder.record(frame);
                    }
                    grabber.stop();
                }
                currentFileIndex++;
            }
            
            // 更新进度：处理完成
            if (progressCallback != null) {
                progressCallback.onProgress("音频合并完成", 100);
            }
        } finally {
            // 5. 释放资源
            recorder.stop();
        }
    }

    /**
     * 从文件路径提取格式（如"output.wav" -> "wav"）
     */
    private String getFileFormat(String filePath) {
        int lastDotIndex = filePath.lastIndexOf('.');
        if (lastDotIndex == -1 || lastDotIndex >= filePath.length() - 1) {
            throw new IllegalArgumentException("输出文件路径格式无效：" + filePath);
        }
        return filePath.substring(lastDotIndex + 1).toLowerCase();
    }
}